#include "ScanLineRasterizerMT.h"
#include <QThread>
#include <QMutex>
#include <QWaitCondition>





ScanLineRasterizerMT::ScanLineRasterizerMT(int numThreads)
	:	AbstractRasterizer(),
		mRenderingThreads(numThreads)
{
	working_threads = new QAtomicInt(0);
	mFpThreads.resize(numThreads);
	mVpThreads.resize(numThreads);
	for (int i = 0; i < numThreads; i++)
	{
		mFpThreads[i] = new ScanLineRasterizerMT_FP_Thread(working_threads, transformed_face_buffer);
		mFpThreads[i]->start();
		mVpThreads[i] = new ScanLineRasterizerMT_VP_Thread(working_threads, transformed_face_buffer);
		mVpThreads[i]->start();
	}
}
ScanLineRasterizerMT::~ScanLineRasterizerMT()
{
	for (int i = 0; i< mRenderingThreads; i++){
		mVpThreads[i]->mAlive = false;
		mVpThreads[i]->mCondition.wakeAll();
		mVpThreads[i]->wait();
		delete mVpThreads[i];

		mFpThreads[i]->mAlive = false;
		mFpThreads[i]->mCondition.wakeAll();
		mFpThreads[i]->wait();
		delete mFpThreads[i];		
	}
}


void ScanLineRasterizerMT::prepareForRender()
{
	mShaderGlobals.viewInv = mShaderGlobals.view;
	mShaderGlobals.viewInv.inverse();

	mVShaderParams.globals = &mShaderGlobals;
	mFShaderParams.globals = &mShaderGlobals;

	cvZero(mShaderGlobals.renderTarget->depthBuffer);
	cvZero(mShaderGlobals.renderTarget->colorBuffer);
}
void ScanLineRasterizerMT::renderMesh(const Mesh& mesh)
{
	//mShaderGlobals.worldViewProj = mesh.transform * mShaderGlobals.view * mShaderGlobals.proj;
	mShaderGlobals.worldViewProj = mesh.transform * mShaderGlobals.view * mShaderGlobals.proj;
	mShaderGlobals.worldViewProj = mShaderGlobals.worldViewProj.transpose();

	transformed_face_buffer.resize(mesh.faces.size());

	*working_threads = mRenderingThreads;

	size_t num_faces = mesh.faces.size();
	size_t num_faces_per_thread = num_faces / mRenderingThreads;

	for (int i = 0; i < mRenderingThreads; i++)
	{
		int start = i*num_faces_per_thread;
		int end = (i+1) * num_faces_per_thread;
		if (i == mRenderingThreads-1){
			end = num_faces-1;	
		}
		mVpThreads[i]->init(start, end, &mesh.faces, mVertexShader, &mShaderGlobals);
	}

	QMutex m;
	QWaitCondition cond;
	{
		QMutexLocker lock(&m);
		while(*working_threads != 0)
			cond.wait(&m, 0);
	}

	*working_threads = mRenderingThreads;
	Real h = mShaderGlobals.renderTarget->height;
	Real yspan = h / mRenderingThreads;

	for (int i = 0; i < mRenderingThreads; i++){
		mFpThreads[i]->init((int)(i*yspan), (int)((i+1)*yspan), i, mRenderingThreads, mFragmentShader, &mShaderGlobals);
	}

	{
		QMutexLocker lock(&m);
		while(*working_threads != 0)
			cond.wait(&m, 0);
	}

}



